package api;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import models.BasicInformation;
import models.InternshipFamiliar;
import models.Subscriber;
import models.User;
import org.junit.Test;
import play.mvc.Http.Response;
import play.mvc.Http.StatusCode;
import com.google.appengine.api.NamespaceManager;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import controllers.Data;
import base.BaseTest;

public class AdminManageUsers extends BaseTest {
	
	@Test
	public void crudTest() {
		 Map<String, String> loginUserParams = new HashMap<String, String>();
		 loginUserParams.put("username", "laura.garcia@B");
		 loginUserParams.put("password", "secret1");
		// Login here so the following request will be authenticated:
		 Response response = POST("/login", loginUserParams);
		 // The following is an action that requires an authenticated user:
		 response = GET("/api/users");
		 assertIsOk(response);
		 InputStream is = new ByteArrayInputStream(response.out.toByteArray());
		 Reader reader = new InputStreamReader(is);
		 Type dataType = new TypeToken<Data<User>>(){}.getType();
		 Data<User> data = new Gson().fromJson(reader, dataType);
		 assertTrue("La residencia sólo tiene 6 usuarios registrados", data.data.size() == 6);
		 response = GET("/api/users?type=admin");
		 assertIsOk(response);
		 is = new ByteArrayInputStream(response.out.toByteArray());
		 reader = new InputStreamReader(is);
		 data = new Gson().fromJson(reader, dataType);
		 assertTrue("La residencia sólo tiene un administrador", data.data.size() == 1);
		 response = GET("/api/users?type=familiar");
		 assertIsOk(response);
		 is = new ByteArrayInputStream(response.out.toByteArray());
		 reader = new InputStreamReader(is);
		 data = new Gson().fromJson(reader, dataType);
		 assertTrue("La residencia sólo tiene tres internos", data.data.size() == 3);
		 response = GET("/api/users?type=capitan");
		 assertStatus(StatusCode.NOT_FOUND,response);
		 response = GET("/api/users?type=internal");
		 assertIsOk(response);
		 is = new ByteArrayInputStream(response.out.toByteArray());
		 reader = new InputStreamReader(is);
		 data = new Gson().fromJson(reader, dataType);
		 assertTrue("La residencia sólo tiene dos internos", data.data.size() == 2);
		 User internal = data.data.get(0);
		 addFamiliar(internal);
	}
	
	private static void addFamiliar(User internal) {
		User familiar = new User();
		familiar.username = "angela.martin";
		familiar.password = "test2012";
		familiar.access = true;
		BasicInformation basicInformation = new BasicInformation();
		familiar.basic_information = basicInformation;
		basicInformation.firstName = "Angela";
		basicInformation.lastName = "Martin";
		Response response = POST("/api/users/" + internal.id + "/familiars", "application/json", new Gson().toJson(familiar));
		assertStatus(StatusCode.CREATED, response);
		String location = response.getHeader("location");
		assertNotNull("Location header musn't be empty", location);
		response = GET(location);
		InputStream is = new ByteArrayInputStream(response.out.toByteArray());
		Reader reader = new InputStreamReader(is);
		familiar = new Gson().fromJson(reader, new TypeToken<User>(){}.getType());
		response = GET("/api/users/" + internal.id + "/familiars");
		is = new ByteArrayInputStream(response.out.toByteArray());
		reader = new InputStreamReader(is);
		Type dataType = new TypeToken<Data<User>>(){}.getType();
		Data<User> data = new Gson().fromJson(reader, dataType);
		response = GET("/api/users/" + internal.id + "/familiars");
		assertIsOk(response);
		is = new ByteArrayInputStream(response.out.toByteArray());
		reader = new InputStreamReader(is);
		data = new Gson().fromJson(reader, dataType);
		assertTrue("El interno " + internal.basic_information.firstName + 
				" debe tener un familiar", data.data.size() == 3);
		response = DELETE("/api/users/" + familiar.id);	
		assertStatus(StatusCode.NO_RESPONSE, response);
		response = GET("/api/users/" + internal.id + "/familiars");
		assertIsOk(response);
		is = new ByteArrayInputStream(response.out.toByteArray());
		reader = new InputStreamReader(is);
		data = new Gson().fromJson(reader, dataType);
		assertTrue("El interno " + internal.basic_information.firstName + 
			" debe tener un familiar", data.data.size() == 2);
		response = GET("/api/users");
		is = new ByteArrayInputStream(response.out.toByteArray());
		reader = new InputStreamReader(is);
		dataType = new TypeToken<Data<User>>(){}.getType();
		data = new Gson().fromJson(reader, dataType);
		assertTrue("La residencia sólo tiene 6 usuarios registrados", data.data.size() == 6);
		showUsers(data.data);
		response = DELETE("/api/users/" + internal.id);	
		assertStatus(StatusCode.NO_RESPONSE, response);
		response = GET("/api/users");
		is = new ByteArrayInputStream(response.out.toByteArray());
		reader = new InputStreamReader(is);
		dataType = new TypeToken<Data<User>>(){}.getType();
		data = new Gson().fromJson(reader, dataType);
		assertTrue("La residencia sólo tiene 5 usuarios registrados", data.data.size() == 5);
		showUsers(data.data);
		response = GET("/api/users?type=internal");
		is = new ByteArrayInputStream(response.out.toByteArray());
		reader = new InputStreamReader(is);
		dataType = new TypeToken<Data<User>>(){}.getType();
		data = new Gson().fromJson(reader, dataType);
		assertTrue("La residencia sólo tiene 1 interno", data.data.size() == 1);
		showUsers(data.data);
	}
	
	private static void showUsers(List<User> users) {
		System.out.println("Users number: " + users.size());
		for(User user : users) {
			System.out.println("Username: " + user.username);
		}
	}
	
}